#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"

void io_list_init(struct io_list *list, void (*destroy)(void *data), int(*match)(const void *key1, const void *key2))
{
	list->size = 0;
	list->destroy = destroy;
	list->match = match;
	list->head = NULL;
	list->tail = NULL;
}

void io_list_destroy(struct io_list *list)
{
	void *data;
	while(io_list_size(list) > 0)
	{
		if(0 == io_list_remove(list, io_list_tail(list), (void**)&data) && NULL != list->destroy)
		{
			list->destroy(data);
		}
	}
	
	memset(list, 0, sizeof(struct io_list));
	return;
}

int io_list_ins_next(struct io_list *list, struct io_list_el *el, const void *data)
{
	struct io_list_el *new_el;
	
	if(NULL == el && 0 != io_list_size(list))
	{
		return -1;
	}
	
	if(NULL == (new_el = (struct io_list_el*)malloc(sizeof(struct io_list_el))))
	{
		return -1;
	}
	
	new_el->data = (void*)data;
	
	if(0 == io_list_size(list))
	{
		list->head = new_el;
		list->tail = new_el;
		new_el->next = NULL;
		new_el->prev = NULL;
	}
	else
	{
		new_el->next = el->next;
		new_el->prev = el;
		
		if(NULL == el->next)
		{
			list->tail = new_el;
		}
		else
		{
			el->next->prev = new_el;
		}
		
		el->next = new_el;
	}
	
	list->size++;
	return 0;
}

int io_list_ins_prev(struct io_list *list, struct io_list_el *el, const void *data)
{
	struct io_list_el *new_el;
	
	if(NULL == el && 0 != io_list_size(list))
	{
		return -1;
	}
	
	if(NULL == (new_el = (struct io_list_el*)malloc(sizeof(struct io_list_el))))
	{
		return -1;
	}
	
	new_el->data = (void*)data;
	
	if(0 == io_list_size(list))
	{
		list->head = new_el;
		list->tail = new_el;
		new_el->next = NULL;
		new_el->prev = NULL;
	}
	else
	{
		new_el->next = el;
		new_el->prev = el->prev;
		
		if(NULL == el->prev)
		{
			list->head = new_el;
		}
		else
		{
			el->prev->next = new_el;
		}
		
		el->prev = new_el;
	}
	
	list->size++;
	return 0;
}

int io_list_remove(struct io_list *list, struct io_list_el *el, void **data)
{
	if(NULL == el && 0 != io_list_size(list))
	{
		return -1;
	}
	
	*data = el->data;
	
	if(el == list->head)
	{
		list->head = el->next;
		
		if(NULL == list->head)
		{
			list->tail = NULL;
		}
		else
		{
			el->next->prev = NULL;
		}
	}
	else
	{
		el->prev->next = el->next;
		
		if(NULL == el->next)
		{
			list->tail = el->prev;
		}
		else
		{
			el->next->prev = el->prev;
		}
	}
	
	free(el);
	
	list->size--;
	return 0;
}
